package com.ttjj.service.player;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.ttjj.entity.map.Coordinate;
import com.ttjj.entity.navi.MinDistance;
import com.ttjj.entity.navi.NextDirectionInfo;
import com.ttjj.entity.navi.TerrainNaviMap;
import com.ttjj.entity.navi.TerrainNaviRoute;
import com.ttjj.entity.player.*;
import com.ttjj.enums.EnumAnimalType;
import com.ttjj.enums.EnumDirection;
import com.ttjj.enums.EnumPropType;
import com.ttjj.service.IPlayerService;
import com.ttjj.service.navigation.TerrainAnalyzer;
import com.ttjj.service.navigation.TerrainNavigation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.testng.collections.Maps;
import org.testng.collections.Sets;

import java.util.*;

/**
 * 实现吗喽
 *
 * @author hhs
 * @date 2024-09-25
 */
@Service
@Slf4j
@Data
public class PlayerV2Service implements IPlayerService {

    private static Boolean isCaculated = false;
//    @Autowired
//    private RedisTemplate<String, String> redisTemplate;

    /**
     * 撞车key
     */
    private static final String BLOCK_PLAY = "blockPlay";

    @Override
    public void start(StartBattleReqVo startBattleReqVo) {
        TerrainAnalyzer.MEPlayerId = startBattleReqVo.getPlayerId();
//        String playerId = startBattleReqVo.getPlayerId();
//        List<String> players = startBattleReqVo.getPlayerIds();
//        int size = players.size();
//        int half = size / 2;
//        int i = players.indexOf(playerId);
//        if (i < half) {
//            for (int j = 0; j < half; j++) {
//                TerrainAnalyzer.FRIEND_PLAY.add(players.get(j));
//            }
//        } else {
//            for (int j = half; j < size; j++) {
//                TerrainAnalyzer.FRIEND_PLAY.add(players.get(j));
//            }
//        }
    }

    @Override
    public Map<String, EnumDirection> getStep(PlayReqVo playReqVo) {
        System.out.println(JSON.toJSONString(playReqVo));
        Map<String, EnumDirection> result = Maps.newHashMap();
        // 1、初始化
        init(playReqVo);
        long gameMills = playReqVo.getGameMills();
        boolean isIn2min = gameMills < 120000L;
        boolean isIn1min = gameMills < 60000L;
        boolean onlyEnemyHasAnimal = onlyEnemyHasAnimal(playReqVo);
        // 2、判断背包状态
        PlayerStateVo ME = TerrainAnalyzer.getME();
        Coordinate meCoordinate = new Coordinate(ME.getX(), ME.getY());

        // 判断是否改成冲撞车
        boolean block = isBlock(ME, isIn1min);

        Coordinate target = null;
        // 2.1、满了-> 回家 + 吃最近道具 + 注意有人会获取到炸弹
        if (Objects.equals(ME.getCarrySize(), ME.getCarried().size()) || isClose(playReqVo, ME, meCoordinate)) {
            log.info("回家");
            target = TerrainNavigation.getNextCod(ME, meCoordinate, TerrainAnalyzer.getNearestDeliverCod(meCoordinate));
        } else {
            if (block) {
                // 获取TOP1对手地址
                MinDistance topPlayer = getTopPlayer(ME, meCoordinate);
                // 2.2.2获取道具
                MinDistance minCostPro = getMinCostPro(playReqVo, ME, meCoordinate, onlyEnemyHasAnimal);
                if (topPlayer.getCost() > minCostPro.getRealCost() + 5) {
                    log.info("碰撞车，去拿工具，min：{}，promin：{}", topPlayer, minCostPro);
                    target = new Coordinate(((PropVo) minCostPro.getTarget()).getX(), ((PropVo) minCostPro.getTarget()).getY());
                } else {
                    target = new Coordinate(((PlayerStateVo) topPlayer.getTarget()).getX(), ((PlayerStateVo) topPlayer.getTarget()).getY());
                    log.info("去兑Top1");
                }
            } else {
                // 2.2.1找动物
                MinDistance minCostAnimal = getMinCostAnimal(playReqVo, ME, meCoordinate, isIn2min);
                // 2.2.2获取道具
                MinDistance minCostPro = getMinCostPro(playReqVo, ME, meCoordinate, onlyEnemyHasAnimal);
                if (minCostAnimal.getCost() > minCostPro.getRealCost() + 5) {
                    log.info("动物车，去拿工具，min：{}，promin：{}", minCostAnimal, minCostPro);
                    target = new Coordinate(((PropVo) minCostPro.getTarget()).getX(), ((PropVo) minCostPro.getTarget()).getY());
                } else {
                    target = new Coordinate(((AnimalStateVo) minCostAnimal.getTarget()).getX(), ((AnimalStateVo) minCostAnimal.getTarget()).getY());
                    log.info("去捉动物");
                }
            }
        }

        // 3、获取下一步方向
        NextDirectionInfo nextDirect = TerrainNavigation.getNextDirect(meCoordinate, target);

        // 4、避免碰撞，如果有碰撞重新选择方向
        nextDirect = TerrainAnalyzer.avoidCrash(ME, meCoordinate, nextDirect, null, null);

        // 5、返回最终结果
        log.info("返回步骤：{}", nextDirect.getNextDirection());
        result.put("moveType", nextDirect.getNextDirection());
        return result;
    }

    /**
     * 判断是否只有敌人有动物
     *
     * @return
     */
    private boolean onlyEnemyHasAnimal(PlayReqVo playReqVo) {
        boolean friendhas = false;
        boolean enemyHas = false;
        List<PlayerStateVo> playerStateVos = playReqVo.getPlayerStateVos();
        for (PlayerStateVo playerStateVo : playerStateVos) {
            boolean friend = TerrainAnalyzer.FRIEND_PLAY.contains(playerStateVo.getPlayerId());
            if (friend && !playerStateVo.getCarried().isEmpty()) {
                friendhas = true;
            }
            if (!friend && !playerStateVo.getCarried().isEmpty()) {
                enemyHas = true;
            }
        }
        return enemyHas && !friendhas;
    }

    /**
     * 获取最小耗费动物
     *
     * @param playReqVo
     * @return
     */
    private MinDistance getMinCostAnimal(PlayReqVo playReqVo, PlayerStateVo ME, Coordinate meCoordinate, boolean isIn2min) {
        MinDistance result = new MinDistance();
        // 2.2、未满-> 找动物、找道具
        List<AnimalStateVo> animalStateVos = playReqVo.getAnimalStateVos();
        double min = Double.MAX_VALUE;
        double minReal = Double.MAX_VALUE;
        AnimalStateVo animal1 = null;
        for (AnimalStateVo animalStateVo : animalStateVos) {
            EnumAnimalType type = animalStateVo.getType();
            Coordinate animal = new Coordinate(animalStateVo.getX(), animalStateVo.getY());
            double terrainDistance1 = TerrainNavigation.getTerrainDistance(meCoordinate, animal, ME.getSpeed());
            double terrainDistance = terrainDistance1 * type.getWeight(ME, isIn2min);
            if (terrainDistance < min) {
                min = terrainDistance;
                animal1 = animalStateVo;
                minReal = terrainDistance1;
            }
        }
        result.setCost(min);
        result.setTarget(animal1);
        result.setRealCost(minReal);
        return result;
    }

    /**
     * 获取最小耗费道具
     *
     * @param playReqVo
     * @return
     */
    private MinDistance getMinCostPro(PlayReqVo playReqVo, PlayerStateVo ME, Coordinate meCoordinate, boolean onlyEnemyHasAnimal) {
        MinDistance result = new MinDistance();
        // 2.2、未满-> 找动物、找道具
        double proMin = Double.MAX_VALUE;
        double proRealMin = Double.MAX_VALUE;
        PropVo pro = null;
        List<PropVo> propVos = playReqVo.getPropVos();
        for (PropVo propVo : propVos) {
            EnumPropType type = propVo.getType();
            Coordinate proCoordinate = new Coordinate(propVo.getX(), propVo.getY());
            double terrainDistance1 = TerrainNavigation.getTerrainDistance(meCoordinate, proCoordinate, ME.getSpeed());
            double terrainDistance = terrainDistance1 * type.getWeight(ME, onlyEnemyHasAnimal);
            if (terrainDistance < proMin) {
                proMin = terrainDistance;
                pro = propVo;
                proRealMin = terrainDistance1;
            }
        }
        result.setCost(proMin);
        result.setTarget(pro);
        result.setRealCost(proRealMin);
        return result;
    }

    /**
     * 获取最小耗费动物
     *
     * @param
     * @return
     */
    private MinDistance getTopPlayer(PlayerStateVo ME, Coordinate meCoordinate) {
        MinDistance result = new MinDistance();
        // 找Top1
        PlayerStateVo top1 = TerrainAnalyzer.ENEMY_PLAYER_RANK.iterator().next();
        Coordinate enemyTop1 = new Coordinate(top1.getX(), top1.getY());
        double terrainDistance1 = TerrainNavigation.getTerrainDistance(meCoordinate, enemyTop1, ME.getSpeed());
        result.setCost(terrainDistance1);
        result.setTarget(top1);
        result.setRealCost(terrainDistance1);
        return result;
    }


    /**
     * 判断自己是不是冲撞车
     *
     * @param me
     * @return
     */
    private boolean isBlock(PlayerStateVo me, boolean isIn1min) {
        if (TerrainAnalyzer.ENEMY_PLAYER_RANK.isEmpty() || isIn1min ) {
//                || Boolean.FALSE.equals(redisTemplate.hasKey(BLOCK_PLAY))) {
            return false;
        }
        int meInnerRank = 0;
        int i = 0;
        for (PlayerStateVo playerStateVo : TerrainAnalyzer.OWN_PLAYER_RANK) {
            if (Objects.equals(playerStateVo, me)) {
                //内部顺序
                meInnerRank = i;
                break;
            }
            i++;
        }
        //判断是否内部最后一名且不是最后一个人的时候
        if (meInnerRank == TerrainAnalyzer.OWN_PLAYER_RANK.size() - 1 && TerrainAnalyzer.OWN_PLAYER_RANK.size() != 1) {
            // 还有没有敌人
            if (TerrainAnalyzer.ENEMY_PLAYER_RANK.isEmpty()) {
                return false;
            }
            PlayerStateVo next = TerrainAnalyzer.ENEMY_PLAYER_RANK.iterator().next();
            // 我的位次
            Integer meRank = me.getRank();
            // 敌人位次
            Integer enemyTop1Rank = next.getRank();
            return meRank < enemyTop1Rank;
//            if (changeBlock) {
//                return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(BLOCK_PLAY, me.getPlayerId(), 6L, TimeUnit.SECONDS));
//            }
        }
        return false;
    }

    public static void main(String[] args) {
        System.out.println(Sets.newHashSet().iterator().next());
    }

    /**
     * 判断是否需要快速回家
     *
     * @return
     */
    private boolean isClose(PlayReqVo playReqVo, PlayerStateVo mePlay, Coordinate me) {
        if (mePlay.getCarried().isEmpty()) {
            return false;
        }
        Integer rank = mePlay.getRank();
        long gameMills = playReqVo.getGameMills();
        Map<String, Object> lastMills = getLastMills(gameMills);
        String type = MapUtil.getStr(lastMills, "type");
        if (rank == playReqVo.getPlayerStateVos().size() - 1 || Objects.equals(type, "3")) {
            Long lastmills = MapUtil.getLong(lastMills, "last");
            long l = lastmills / 100;
            double terrainDistance = TerrainNavigation.getTerrainDistance(me, TerrainAnalyzer.getNearestDeliverCod(me), mePlay.getSpeed());

            boolean b = l - terrainDistance < 10;
            if (b) {
                log.info("走快速回家，还剩次数：" + l + ", 距离步数：" + terrainDistance);
            }
            return b;
        }
        return false;
    }

    /**
     * @param gameMills
     * @return
     */
    private Map<String, Object> getLastMills(long gameMills) {
        Map<String, Object> result = new HashMap<>();
        long lastOne = 60 * 1000 - gameMills;
        if (lastOne > 0) {
            result.put("last", lastOne);
            result.put("type", 1);
            return result;
        }
        long lastTwo = 120 * 1000 - gameMills;
        if (lastTwo > 0) {
            result.put("last", lastTwo);
            result.put("type", 2);
            return result;
        }
        long lastThree = 180 * 1000 - gameMills;
        if (lastThree > 0) {
            result.put("last", lastThree);
            result.put("type", 3);
        }
        return result;
    }


    /**
     * 初始化数据
     *
     * @param reqVo
     */
    private static void init(PlayReqVo reqVo) {
        // 初始化地图
        TerrainAnalyzer.initMap(reqVo);
        boolean isCalculating = TerrainNavigation.isCalculating();
        Map<Integer, TerrainNaviRoute> effectiveRouteMap = TerrainNaviMap.getEffectiveRouteMap();
        //是否有铲子
        Set<EnumPropType> propTypes = Sets.newHashSet(TerrainAnalyzer.getME().getHoldingProps());
        boolean hasShovel = propTypes.contains(EnumPropType.Shovel);
        // 判断生效行进图是否为空
        boolean block = MapUtil.isEmpty(effectiveRouteMap);
        if (!isCalculating) {
            TerrainNavigation.reset(block, hasShovel);
            System.out.println("计算好了");
        }
    }
}
